#include "common/common.h"
#include "device_manager.h"

DeviceManager::DeviceManager(void)
{
}

DeviceManager::~DeviceManager(void)
{
}


bool DeviceManager::QueryDevice(REFCLSID clsidDeviceClass)
{
	HRESULT hr = NOERROR;

	ICreateDevEnum * enumHardware = NULL;
	hr = CoCreateInstance(CLSID_SystemDeviceEnum,
		NULL,
		CLSCTX_ALL,
		IID_ICreateDevEnum,
		(void**)&enumHardware);
	if (FAILED(hr) || !enumHardware)
	{
		return false;
	}
	AUTO_RELEASE(ICreateDevEnum, enumHardware);

	IEnumMoniker *  enumMoniker = NULL;
	hr = enumHardware->CreateClassEnumerator(
		clsidDeviceClass, &enumMoniker, 0);
	if (FAILED(hr) || !enumMoniker)
	{
		return false;
	}
	AUTO_RELEASE(IEnumMoniker, enumMoniker);

	enumMoniker->Reset();

	char  displayName[1024];
	char  friendlyName[256];
	ULONG fetched = 0;
	IMoniker * moniker = NULL;

	while(SUCCEEDED(enumMoniker->Next(1, &moniker, &fetched)) && fetched)
	{
		if (!moniker)
		{
			continue;
		}

		// Get display name
		WCHAR * wzDisplayName      = NULL;
		hr = moniker->GetDisplayName(NULL, NULL, &wzDisplayName);
		if(FAILED(hr))
			continue;

		WideCharToMultiByte(CP_ACP, 0, wzDisplayName, -1, displayName, 1024, "", NULL);
		CoTaskMemFree(wzDisplayName);

		IPropertyBag * propertyBag = NULL;
		hr = moniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&propertyBag);
		if(FAILED(hr))
			continue;
		AUTO_RELEASE(IPropertyBag, propertyBag);

		// Get friendly name
		VARIANT name;
		name.vt = VT_BSTR;
		hr = propertyBag->Read(L"FriendlyName", &name, NULL);
		if (FAILED(hr))
			continue;

		friendlyName[0] = 0;
		WideCharToMultiByte(CP_ACP, 0, name.bstrVal, -1,
			friendlyName, 256, NULL, NULL);

		IBaseFilter *  filter      = NULL;
		hr = moniker->BindToObject(0, 0, IID_IBaseFilter, (void**)&filter);
		if (FAILED(hr))
			continue;
		//AUTO_RELEASE(IBaseFilter, filter);

		// get type
		DeviceType type = GetDeviceType(filter);
		if(type == DT_UNKNOWN)
			continue;

		// Save this device
		Device::pointer device(new Device);
		device->m_type = type;
		device->m_display_name = displayName;
		device->m_friendly_name = friendlyName;
		device->m_base_filter = filter;

		switch(type)
		{
		case DT_VIDEO:
			m_video_device_vec.push_back(device);
			break;
		case DT_AUDIO:
			m_audio_device_vec.push_back(device);
			break;
		default:
			LOG_WARN("%s, unbelievale, what's this type %d", __FUNCTION__, type);
			break;
		}
	}

	return TRUE;
}

DeviceType DeviceManager::GetDeviceType(IBaseFilter * inFilter)
{
	// Check if WDM analog
	IAMAnalogVideoDecoder * pDecoder = NULL;
	IAMCameraControl *      pCamera  = NULL;
	IAMVideoProcAmp *		pAmp	 = NULL;
	inFilter->QueryInterface(IID_IAMAnalogVideoDecoder, (void **)&pDecoder);
	inFilter->QueryInterface(IID_IAMCameraControl, (void **)&pCamera);
	inFilter->QueryInterface(IID_IAMVideoProcAmp, (void **)&pAmp);
	if (pDecoder || pCamera || pAmp)
	{
		SAFE_RELEASE(pDecoder);
		SAFE_RELEASE(pCamera);
		SAFE_RELEASE(pAmp);
		return DT_VIDEO;
	}

	// Check if VFW analog
	//IAMVfwCaptureDialogs * pVfwDlgs = NULL;
	//inFilter->QueryInterface(IID_IAMVfwCaptureDialogs, (void **)&pVfwDlgs);
	//if (pVfwDlgs)
	//{
	//	SAFE_RELEASE(pVfwDlgs);
	//	return DT_VIDEO;
	//}

	// Check if audio capture device
	IAMAudioInputMixer * pAudioMixer = NULL;
	inFilter->QueryInterface(IID_IAMAudioInputMixer, (void **)&pAudioMixer);
	if (pAudioMixer)
	{
		SAFE_RELEASE(pAudioMixer);
		return DT_AUDIO;
	}

	return DT_UNKNOWN;
}